package lte

import (
	"math"
	"math/cmplx"

	"gitee.com/thubcc/mobile/utils"
)

type ScanPss struct {
	fd utils.Array2
	rg []int
}

var (
	ScanPssAll *ScanPss
)

func BuildScanPss(n int) *ScanPss {
	fd := utils.NewArray2d(3, 9600)
	fft := utils.NewFFT(9600)
	ifft := tx_ifft_plan[6]
	for t, pss := range LTEPSS {
		copy(ifft.Buf, pss.Fd())
		ifft.Execute()
		copy(fft.Buf[:128], ifft.Buf)
		for i := 128; i < 9600; i++ {
			fft.Buf[i] = 0.0 + 0.0i
		}
		fft.ExecuteAndScale(1.0 / 9600.)
		for i, v := range fft.Buf {
			fft.Buf[i] = cmplx.Conj(v)
		}
		copy(fd.D[t], fft.Buf)
	}
	rg := make([]int, 2*n+1)
	for i := -n; i <= n; i++ {
		rg[i+n] = i * 25
	}
	return &ScanPss{fd, rg}
}

func (self *ScanPss) fd_pss(t, s int) []complex128 {
	return utils.CycleShift(self.fd.D[t], s)
}

func (self *ScanPss) Frequency(n int) int {
	return self.rg[n] * 200
}

func (self *ScanPss) SearchPSS2D(rfd []complex128, init_f float64) ([3]int, float64, [][][]float64) {
	ps := 3
	hf := 9600
	dl := len(rfd)
	acc := dl / hf
	res := make([][][]float64, ps)
	fft := utils.NewFFT(hf)
	ifft := utils.NewIFFT(hf)
	for t := 0; t < ps; t++ {
		res[t] = make([][]float64, len(self.rg))
		for k := range self.rg {
			res[t][k] = make([]float64, hf)
		}
	}
	for k, df := range self.rg {
		drc := 1.0 + float64(df*200)/init_f
		for fn := 0; fn < acc; fn++ {
			ppos := int(float64(fn*hf)/drc + 0.5)
			if ppos+hf > dl {
				copy(fft.Buf[:dl-ppos], rfd[ppos:])
				for i := dl - ppos; i < hf; i++ {
					fft.Buf[i] = 0. + 0.i
				}
			} else {
				copy(fft.Buf, rfd[ppos:ppos+hf])
			}
			fft.Execute()
			for t := 0; t < ps; t++ {
				pss_fft := self.fd_pss(t, df)
				for i, v := range fft.Buf {
					ifft.Buf[i] = v * pss_fft[i]
				}
				ifft.ExecuteAndScale(1.0 / float64(hf))
				for i, v := range ifft.Buf {
					res[t][k][i] += cmplx.Abs(v)
				}
			}
		}
	}
	idx, amp := utils.AbsMax3D(res)
	return idx, amp, res
}

func AFCByCP(rfd []complex128, symbol_sz int) float64 {
	fr := 0.0 + 0.i
	for i, v := range rfd[symbol_sz:] {
		fr += v * cmplx.Conj(rfd[i])
	}
	return cmplx.Phase(fr) / (2. * math.Pi) * 15e3
}

func (self *ScanPss) SearchPSS(rfd []complex128, init_f float64) (float64, float64, int, int) {
	idx, amp, _ := self.SearchPSS2D(rfd[:19200*2], init_f)
	df := self.Frequency(idx[1])
	// log.Info("PSS 1 ", df)
	f := AFCByCP(rfd, 128)
	// log.Info("CP 1 ", f)
	ddf := math.Round((float64(df)-f)/15e3)*15e3 + f
	pos := 9600 - 960 + idx[2] + 128
	pos %= 9600
	return ddf, amp, idx[0], pos
}
